% estimaLoopOuter.m
% Formerly ESTIMA_LOOP_PARALLEL
% This loop has been written for Paralell Computation


%% 1.Organize Output storage (Broadcast variables)
logprior_mat(:,2)= -inf*ones(nstrvals,1);
loglikel_mat(:,2)= -inf*ones(nstrvals,1);
logpostd_mat(:,2)= -inf*ones(nstrvals,1);
parmodemat=nan(numpar, nstrvals);
hessianMat=zeros( length(parposest), length(parposest) , nstrvals ); 

stdLoopMat=nan(length(parposest), nstrvals); 
mat_exitflag=nan(1, nstrvals);
mat_iterations=nan(1, nstrvals);
mat_time=nan(1, nstrvals);

%% 2. Assign default values to ESTIMOPT if they do not exist
if ~exist('estimopt', 'var'); estimopt = []; end;
[~,estimopt]   =ch_field(estimopt,'TolFun',1e-5);
[~,estimopt]   =ch_field(estimopt,'MaxFuneval',200000);
[~,estimopt]   =ch_field(estimopt,'MaxIter',400);
[junk,estimopt]=ch_field(estimopt,'Display','iteration');
estimopt.UseParallel='always';
% if case_estima == 4; % when using Simann
%     % pass in special inputs
%     [~,estimopt]=ch_field(estimopt,'sa_t',1e7);
%     [~,estimopt]=ch_field(estimopt,'sa_rt',0.9);
%     [~,estimopt]=ch_field(estimopt,'sa_nt',5);
%     [~,estimopt]=ch_field(estimopt,'sa_ns',20);
%     [~,estimopt]=ch_field(estimopt,'rseed',999);
%     [~,estimopt]=ch_field(estimopt,'sa_neps',4);
%     [~,estimopt]=ch_field(estimopt,'sa_eps',1e-5); % convergenece criteria
%     [~,estimopt]=ch_field(estimopt,'sa_maxeval',12*1e6);
%     [~,estimopt]=ch_field(estimopt,'sa_maxiter',3*1e6);
% end


%% 3  Preliminary assigments and truncations before loop begins
%     Formerly known as INDMAT, this is the matrix of transformations
%     PARVECMODE is an empty vector with the calibrated values in
parestmat=zeros(length(parposest),2);

%% 4. flagParallel==0 only
if flagParallel==0
    tab_loop=emptycell(numpar+7,nstrvals+1);
    tab_loop(1:numpar,1)=parnames;
    tab_loop(numpar+2:end,1)={'logPost';'logLikel';'Number';'Iteration count';'exitflag';'minutes'};
    cd(outpath);save tab_loop;cd(cucd);
end

%% 5. Additional inputs used in the estimation (estimStructure)
estimStructure.parVec=parvec;
estimStructure.parPosEst=parposest;
estimStructure.transMat=partrmat(parposest, :);
estimStructure.trainVec=trainvec;
estimStructure.ssPosEst=ssposest;
estimStructure.flagSilent=flagParallel;
tic;

%% 6. Assign Optimization function (funcOptimization)
flagOptimization=0;
if ~isempty(strmatch(upper(caseEstima),'CSMINWEL','exact'));
    funcOptimization=@lmjMinCsminwel;
    disp('Using Csminwel for Optimization');
    flagOptimization=1;
end
if ~isempty(strmatch(upper(caseEstima),'FMINCON','exact'));
    funcOptimization=@lmjMinFmincon;
    disp('Using fmincon for Optimization');
    flagOptimization=1;
end
if flagOptimization~=1
    error('Could Not Assign an Optimization Routine')
end

%% 7. Assign Loop depending on the estimation case 
switch flagParallel 
    case 0 
        estimaLoopSingle
    case 1 
        estimaLoopParallel 
end 

%% 9. Create Optimat, matrix of Iterations | Exit Flag and Mat_
optimat=[mat_iterations; mat_exitflag; mat_time];
dispaj('Total time in minutes=',sum(optimat(3,:)));

%% 8. Save Workspace 
try
    cd(outpath);
    save workspace;
    cd(cucd);
    disp('Saved Workspace'); 
catch
    disp('Could not save workspace');
end

clear icount likel nx ny nz lprior_ss lpriord nstrvals; 

%% 1. Assign Flag Structure 
flagStru.hessianDone=0; 
flagStru.spectrumDone=0; 
flagStru.tableDone=0; 
flagStru.handleChanged=0; 
disp('Assigned flagStru'); 